;; ================
;; DATA ABSTRACTION
;; ================

;; The value is always the first value of the generator.
(define get-value car)

;; A generator's producing procedure needs to be applied to get the
;; next thing.
(define (get-next a-gen)
  ((cdr a-gen)))

;; A generator is only a tuple containing the current value and the
;; procedure to create the next value
(define (make-gen proc start)
  (cons start
        (λ ()
          (make-gen proc (proc start)))))

(define STOP-SYMBOL 'none)

;; ========
;; EXAMPLES
;; ========

;; An infinite list of numbers.
(define natural-numbers
  (make-gen (λ (x) (+ x 1))
            0))

;; A limited list of natural numbers.
(define (limited-natural-numbers limit)
  (make-gen (λ (x)
              (cond [(< x limit) (+ x 1)]
                    [else STOP-SYMBOL]))
            0))

;; Print a certain amount of natural numbers.
(define (print-natural-numbers natural-numbers limit)
  (let ([current-number (get-value natural-numbers)])
    (cond
      [(and (symbol? current-number) (eq? current-number STOP-SYMBOL))
       (display (simple-format #f "No more numbers available!\n"))]
      [(< current-number limit)
       (display (simple-format #f "~a\n" current-number))
       (print-natural-numbers (get-next natural-numbers) limit)]
      [else
       (display (simple-format #f "Done.\n"))])))
